
#include "Publishers.h"
#include "PublisherBase.h"

using namespace std;
using namespace ttg;
using namespace ttg::structures;
using namespace ttg::services;

//---------------------
//--- PublisherBase ---
//---------------------

//private

PublisherBase *PublisherBase::ref = NULL;

PublisherBase::PublisherBase()
	:Service("PublisherBase", NULL)
{
	publishers = NULL;
	makeRegistration();
}

PublisherBase::~PublisherBase()
{
	SAFE_DELETE(publishers);
	cp = NULL;
}

//protected

void PublisherBase::startUnSafe(vector<Service *> &deps, const char *params)
{
	SAFE_DELETE(publishers);
	publishers = Dictionary<PublisherInfo>::create(50);
	cp = new CommonPublisher();
	list<TTGTriple<const char *,
				   Subscriber *,
				   void (*)(Subscriber *ss, Event *ev)>>::iterator it = delayed.begin();
	while (it != delayed.end())
	{
		if (this->subscribe(it->getFirst(), it->getSecond(), it->getThird()))
			it = delayed.erase(it);
		else
			it++;
	}
}

void PublisherBase::stopUnSafe()
{
	SAFE_DELETE(publishers);
	delayed.clear();
}

//public

void PublisherBase::regPublisher(PublisherInfo *p)
{
	publishers->add(p);
	string name(p->getName());
	list<TTGTriple<const char *,
				   Subscriber *,
				   void (*)(Subscriber *ss, Event *ev)>>::iterator it = delayed.begin();
	while (it != delayed.end())
	{
		if (name == it->getFirst())
		{
			p->addSubscriber(it->getSecond(), it->getThird());
			it = delayed.erase(it);
		}
		else
			it++;
	}
}

void PublisherBase::unregPublisher(PublisherInfo *p)
{
	this->publishers->remove(p);
}

bool PublisherBase::subscribe(const char *publisher, Subscriber *s, void (*d)(Subscriber *ss, Event *ev))
{
	if (publishers == NULL)
		return false;
	PublisherInfo *pi = publishers->get(publisher);
	if (pi != NULL)
	{
		pi->addSubscriber(s, d);
		return true;
	}
	else
		return false;
}

void PublisherBase::subscribeAsSoonAsPossible(const char *publisher,
											  Subscriber *s,
											  void (*d)(Subscriber *ss, Event *ev))
{
	if (!this->subscribe(publisher, s, d))
		this->delayed.push_back(TTGTriple<const char *,
										   Subscriber *,
										   void (*)(Subscriber *ss, Event *ev)>(publisher, s, d));
}

void PublisherBase::desubscribe(const char *publisher, Subscriber *s)
{
	PublisherInfo *pi = publishers->get(publisher);
	if (pi != NULL)
		pi->removeSubscriber(s);
}
